#include "AHB.h"
#include "Fpga.h"
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <stdarg.h>
#include <memory.h>
extern unsigned char mutex;
/******************************************************/
// 等待一段时间
/******************************************************/
void wait(int time)
{
    int i = 0;
    while (i < time)
    {
        i++;
    }
}
/******************************************************/
// 功能： 打开 AHB 总线，调用底层的 FPGA 设备相关函数
/******************************************************/
void Open_AHB()
{
    Open_FPGA();
}
/******************************************************/
// 功能： 关闭 AHB 总线
/******************************************************/
void Close_AHB()
{
    Close_FPGA();
}
/******************************************************/
// 功能：从 AHB 总线读取 2 字节数据
// 参数：addr - 读地址
/******************************************************/
unsigned short AHB_Read(unsigned int addr)
{
    unsigned short read_context;
    while (mutex == 1)
        ;
    mutex = 1;
    read_context = FPGA_ReadShort_Fast(addr);
    wait(5000);
    mutex = 0;
    return read_context;
}
/******************************************************/
// 功能：通过 AHB 总线写入 2 字节数据
// 参数：addr-- 写地址；data-- 写入的数据
/******************************************************/
void AHB_Write(unsigned int addr, unsigned short data)
{
    while (mutex == 1)
        ;
    mutex = 1;
    FPGA_WriteShort(addr, data);
    FPGA_WriteShort(addr, data);
    FPGA_ReadShort_Fast(addr);
    mutex = 0;
}
/******************************************************/
// 功能：通过 AHB 总线从 RAM 写读出数据
// 参数：addr_addr-- 写地址在 AHB 总线的地址
//     data_addr-- 写入的数据在 AHB 总线的地址
//     start_addr-- 从 RAM 读数据的起始地址
//     len-- 读出的数据长度
//     buf-- 读出数据的缓冲区
/******************************************************/
void AHB_Memory_Read(unsigned int addr_addr, unsigned int data_addr, unsigned int start_addr, unsigned int len, unsigned short *buf)
{
    while (mutex == 1)
        ;
    mutex = 1;
    unsigned int i = 0;
    for (i = 0; i < len; i++)
    {
        FPGA_WriteShort(addr_addr, start_addr + i);
        wait(25);
        buf[i] = FPGA_ReadShort_Fast(data_addr);
        wait(25);
    }
    mutex = 0;
}
/******************************************************/
// 功能：通过 AHB 总线向 RAM 写写入数据
// 参数：addr_addr-- 写地址在 AHB 总线的地址
//     data_addr-- 写入的数据在 AHB 总线的地址
//     start_addr-- 从 RAM 读数据的起始地址
//     len-- 读出的数据长度
//     buf-- 读出数据的缓冲区
/******************************************************/
void AHB_Memory_Write(unsigned int addr_addr, unsigned int data_addr, unsigned int start_addr, unsigned int len, unsigned short *buf)
{
    while (mutex == 1)
        ;
    mutex = 1;
    unsigned int i = 0;
    for (i = 0; i < len; i++)
    {
        FPGA_WriteShort(addr_addr, start_addr + i);
        FPGA_WriteShort(data_addr, buf[i]);
    }
    mutex = 0;
}
/******************************************************/
// 功能：通过 AHB 总线从 RAM 写读出数据，快速模式
// 参数：addr_addr-- 读地址在 AHB 总线的地址
//     data_addr-- 读出的数据在 AHB 总线的地址
//     start_addr-- 从 RAM 读数据的起始地址
//     len-- 读出的数据长度
//     buf-- 读出数据的缓冲区
/******************************************************/
void AHB_Memory_Read_Fast(unsigned int addr_addr, unsigned int data_addr, unsigned int start_addr, unsigned int len, unsigned short *buf)
{
    while (mutex == 1)
        ;
    mutex = 1;
    unsigned int i = 0;
    FPGA_WriteShort(addr_addr, start_addr);
    for (i = 0; i < len; i++)
        buf[i] = FPGA_ReadShort_Fast(data_addr);
    mutex = 0;
}
/******************************************************/
// 功能：通过 AHB 总线向 RAM 写入数据，快速模式
// 参数：addr_addr-- 写地址在 AHB 总线的地址
//     data_addr-- 写入的数据在 AHB 总线的地址
//     start_addr-- 从 RAM 读数据的起始地址
//     len-- 写入的数据长度
//     buf-- 写入数据的缓冲区
/******************************************************/
void AHB_Memory_Write_Fast(unsigned int addr_addr, unsigned int data_addr, unsigned int start_addr, unsigned int len, unsigned short *buf)
{
    while (mutex == 1)
        ;
    mutex = 1;
    unsigned int i = 0;
    FPGA_WriteShort(addr_addr, start_addr);
    for (i = 0; i < len; i++)
        FPGA_WriteShort(data_addr, buf[i]);
    mutex = 0;
}
/******************************************************/
// 功能：通过 AHB 总线向 FIFO 读出数据
// 参数：clk_addr-- 读时钟在 AHB 总线的地址
//     data_addr-- 读出的数据在 AHB 总线的地址
//     empty_addr--FIFO 空标志位地址
//     len-- 读出的数据长度
//     buf-- 读出数据的缓冲区
//     mode-- FIFO读取模式(可选，为1时表示读取到FIFO为空)
/******************************************************/
int AHB_FIFO_Read(unsigned int clk_addr, unsigned int data_addr, unsigned int full_addr, unsigned int empty_addr, unsigned int almost_empty_addr, unsigned int valid_addr, unsigned int len, unsigned short *buf, ...)
{
    while (mutex == 1)
        ;
    mutex = 1;
    int length = 0;
    int mode;
    va_list sArgv;
    va_start(sArgv, buf);
    mode = va_arg(sArgv, int);
    va_end(sArgv);
    unsigned int valid = 0;
    if (mode != 1)
    {
        // Valid Control
        unsigned int i = 0;
        length = len;
        for (i = 0; i < len; i++)
        {
            FPGA_WriteShort(clk_addr, 0);
            FPGA_WriteShort(clk_addr, 1);
            valid = FPGA_ReadShort(valid_addr);
            while (valid == 0)
            {
                FPGA_WriteShort(clk_addr, 0);
                FPGA_WriteShort(clk_addr, 1);
                valid = FPGA_ReadShort(valid_addr);
            }
            buf[i] = FPGA_ReadShort(data_addr);
        }
        FPGA_WriteShort(clk_addr, 0);
    }
    else
    {
        while (valid == 0)
        {
            FPGA_WriteShort(clk_addr, 0);
            FPGA_WriteShort(clk_addr, 1);
            valid = FPGA_ReadShort(valid_addr);
        }
        while (valid == 1)
        {
            buf[length] = FPGA_ReadShort(data_addr);
            length = length + 1;
            if (length == len)
            {
                // length = -1;
                break;
            }
            FPGA_WriteShort(clk_addr, 0);
            FPGA_WriteShort(clk_addr, 1);
            valid = FPGA_ReadShort(valid_addr);
        }
        while (length < 1000)
        {
            while (valid == 0)
            {
                FPGA_WriteShort(clk_addr, 0);
                FPGA_WriteShort(clk_addr, 1);
                valid = FPGA_ReadShort(valid_addr);
            }
            while (valid == 1)
            {
                buf[length] = FPGA_ReadShort(data_addr);
                length = length + 1;
                if (length == len)
                {
                    // length = -1;
                    break;
                }
                FPGA_WriteShort(clk_addr, 0);
                FPGA_WriteShort(clk_addr, 1);
                valid = FPGA_ReadShort(valid_addr);
            }
        }
        FPGA_WriteShort(clk_addr, 0);
    }
    mutex = 0;
    return length;
}

int AHB_FIFO_Buf_Read(unsigned int clk_addr, unsigned int data_addr, unsigned int valid_addr, int len, unsigned short *buf, int buf_tail)
{
#if TIMETEST
    struct timeval start, stop;
#endif
    int read_len = 0;
    int valid = 0;
    while (valid == 0)
    {
        FPGA_WriteShort(clk_addr, 0);
        FPGA_WriteShort(clk_addr, 1);
        valid = FPGA_ReadShort(valid_addr);
    }
    while (valid == 1)
    {
#if TIMETEST
        gettimeofday(&start, NULL);
#endif
        buf[buf_tail % len] = FPGA_ReadShort(data_addr);
        buf_tail = buf_tail + 1;
        read_len = read_len + 1;
        FPGA_WriteShort(clk_addr, 0);
        FPGA_WriteShort(clk_addr, 1);
        valid = FPGA_ReadShort(valid_addr);
#if TIMETEST
        gettimeofday(&stop, NULL);
        tmpfiforead = (double)stop.tv_sec - start.tv_sec + 1.0e-6 * (stop.tv_usec - start.tv_usec);
        if (tmpfiforead > maxfiforead)
            maxfiforead = tmpfiforead;
        if (tmpfiforead < minfiforead)
            minfiforead = tmpfiforead;
#endif
    }
    while (read_len < 1000)
    {
        while (valid == 0)
        {
            FPGA_WriteShort(clk_addr, 0);
            FPGA_WriteShort(clk_addr, 1);
            valid = FPGA_ReadShort(valid_addr);
        }
        while (valid == 1)
        {
#if TIMETEST
            gettimeofday(&start, NULL);
#endif
            buf[buf_tail % len] = FPGA_ReadShort(data_addr);
            buf_tail = buf_tail + 1;
            read_len = read_len + 1;
            FPGA_WriteShort(clk_addr, 0);
            FPGA_WriteShort(clk_addr, 1);
            valid = FPGA_ReadShort(valid_addr);
#if TIMETEST
            gettimeofday(&stop, NULL);
            tmpfiforead = (double)stop.tv_sec - start.tv_sec + 1.0e-6 * (stop.tv_usec - start.tv_usec);
            if (tmpfiforead > maxfiforead)
                maxfiforead = tmpfiforead;
            if (tmpfiforead < minfiforead)
                minfiforead = tmpfiforead;
#endif
        }
    }
    FPGA_WriteShort(clk_addr, 0);
    return buf_tail;
}

/******************************************************/
// 功能：通过 AHB 总线向 FIFO 写入数据
// 参数：clk_addr-- 写时钟在 AHB 总线的地址
//     data_addr-- 写入的数据在 AHB 总线的地址
//     len-- 写入的数据长度
//     buf-- 写入数据的缓冲区
/******************************************************/
void AHB_FIFO_Write(unsigned int clk_addr, unsigned int data_addr, unsigned int len, unsigned short *buf)
{
    while (mutex == 1)
        ;
    mutex = 1;
    unsigned int i = 0;
    for (i = 0; i < len; i++)
    {
        FPGA_WriteShort(clk_addr, 0);
        FPGA_WriteShort(data_addr, buf[i]);
        FPGA_WriteShort(clk_addr, 1);
    }
    mutex = 0;
}
